package com.ddwl.order.service;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.ddwl.common.constant.*;
import com.ddwl.common.exception.IllegalException;
import com.ddwl.common.exception.ParamException;
import com.ddwl.common.feign.api.*;
import com.ddwl.common.util.BeanConverUtils;
import com.ddwl.order.dao.OrderInfoDao;
import com.ddwl.order.dao.OrderInfoMasterDao;
import com.ddwl.order.dao.OrderPayDao;
import com.ddwl.order.dao.model.OrderInfo;
import com.ddwl.order.dao.model.OrderInfoMaster;
import com.ddwl.order.dao.model.OrderPay;
import com.ddwl.schema.bo.funds.PaymentCreAndPayBo;
import com.ddwl.schema.bo.gate.DingTalkBo;
import com.ddwl.schema.bo.gate.wechat.WxTemplateMsgBo;
import com.ddwl.schema.bo.message.TempSentSmsBo;
import com.ddwl.schema.bo.order.ChangeStockBo;
import com.ddwl.schema.bo.order.OrderPayBo;
import com.ddwl.schema.util.DateUtil;
import com.ddwl.schema.vo.funds.OrderPaymentVo;
import com.ddwl.schema.vo.order.OrderInfoVo;
import com.ddwl.schema.vo.order.OrderPhaseVo;
import com.ddwl.schema.vo.order.OrderSpuVo;
import com.ddwl.schema.vo.shop.ShopVo;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.aop.framework.AopContext;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 类OrderPayServer.java的实现描述：订单支付处理
 *
 * @author zach
 * @Date :2020-06-02 17:11.
 */
@Service
public class OrderPayServer {

    @Resource
    private OrderPayDao orderPayDao;
    @Resource
    private OrderInfoServer orderInfoServer;
    @Resource
    private OrderInfoDao orderInfoDao;
    @Resource
    private OrderSpuServer orderSpuServer;
    @Resource
    private OrderPhaseServer orderPhaseServer;
    @Resource
    private OrderInfoMasterDao orderInfoMasterDao;
    @Resource
    private FundsApi fundsApi;
    @Resource
    private RabbitTemplate rabbitTemplate;
    @Resource
    private MessageApi messageApi;
    @Resource
    private ShopApi shopApi;
    @Resource
    private GoodsApi goodsApi;
    @Resource
    private GateApi gateApi;
    @Resource
    private UserApi userApi;



    /**
     * 创建订单支付信息
     */
    public OrderPay createOrderPay(OrderInfo orderInfo ){
        Instant now = Instant.now();
        OrderPay addPay = BeanConverUtils.convertBean(orderInfo,OrderPay.class,"id");
        addPay.setAmount(orderInfo.getRealAmount());
        addPay.setPayType(OrderEnum.PayType.WX.getCode());
        addPay.setTradeStatus(OrderEnum.PayStatus.PRE.getCode());
        addPay.setSubject(OrderEnum.WX_ORDER_BODY);
        addPay.setProduct(orderInfo.getProduct());
        addPay.setOrderId(orderInfo.getId());
        addPay.setMasterOrderId(orderInfo.getMasterOrderId());
        if(OrderEnum.PayType.PHASE.getCode().equals(orderInfo.getPayType())){
            OrderPhaseVo orderPhaseVo = orderPhaseServer.getNoPayPhase(orderInfo.getId());
            IllegalException.isTrue(now.isBefore(orderPhaseVo.getStartTime()),"当前阶段付款时间还没到");
            IllegalException.isTrue(now.isAfter(orderPhaseVo.getEndTime()),"当前阶段付款时间已经结束");
            IllegalException.isNull(orderPhaseVo);
            addPay.setPhaseId(orderPhaseVo.getId());
            addPay.setAmount(orderPhaseVo.getAmount());
            addPay.setExpirationTime(orderPhaseVo.getEndTime());
            orderInfo.setThisPayAmount(orderPhaseVo.getAmount());
            orderInfo.setExpirationTime(orderPhaseVo.getEndTime());
            orderInfo.setStartPayTime(orderPhaseVo.getStartTime());
        }else {
            orderInfo.setThisPayAmount(addPay.getAmount());
            orderInfo.setStartPayTime(addPay.getGmtCreated());
            orderInfo.setExpirationTime(addPay.getExpirationTime());
        }
        addPay.setPayTimes(0);
        orderPayDao.insert(addPay);
        return addPay;
    }

    
    /**
     * 创建订单支付信息
     */
    public OrderPay createOrderPayNew(List<OrderInfo> orderInfoList ){
        Instant now = Instant.now();
        ParamException.isTrue(orderInfoList==null||orderInfoList.size()==0,"订单为空");
        OrderInfo orderInfo = orderInfoList.get(0);
        OrderPay addPay = BeanConverUtils.convertBean(orderInfo,OrderPay.class,"id");
        BigDecimal realAmount = orderInfoList.stream().map(o -> o.getRealAmount()).reduce(BigDecimal.ZERO, BigDecimal::add);
        addPay.setAmount(realAmount);
        orderInfo.setThisPayAmount(realAmount);
        addPay.setPayType(OrderEnum.PayType.WX.getCode());
        addPay.setTradeStatus(OrderEnum.PayStatus.PRE.getCode());
        addPay.setSubject(OrderEnum.WX_ORDER_BODY);
        addPay.setOrderId(orderInfo.getMasterOrderId());
        if(OrderEnum.PayType.PHASE.getCode().equals(orderInfo.getPayType())){
            OrderPhaseVo orderPhaseVo = orderPhaseServer.getNoPayPhase(orderInfo.getId());
            IllegalException.isTrue(now.isBefore(orderPhaseVo.getStartTime()),"当前阶段付款时间还没到");
            IllegalException.isTrue(now.isAfter(orderPhaseVo.getEndTime()),"当前阶段付款时间已经结束");
            IllegalException.isNull(orderPhaseVo);
            addPay.setPhaseId(orderPhaseVo.getId());
            addPay.setAmount(orderPhaseVo.getAmount());
            addPay.setExpirationTime(orderPhaseVo.getEndTime());
            orderInfo.setThisPayAmount(orderPhaseVo.getAmount());
            orderInfo.setExpirationTime(orderPhaseVo.getEndTime());
            orderInfo.setStartPayTime(orderPhaseVo.getStartTime());
        }
        addPay.setPayTimes(0);
        orderPayDao.insert(addPay);
        return addPay;
    }



    @Transactional(rollbackFor = Exception.class)
    public String preWxPayNew(OrderPayBo orderPayBo){
        OrderInfoMaster orderInfoMaster = orderInfoMasterDao.selectByPrimaryKey(orderPayBo.getOrderId());
        if (orderInfoMaster!=null){
            List<OrderInfo> orderInfoList = orderInfoServer.getUserMasterOrder(orderPayBo.getOrderId(),orderPayBo.getOperator());
            OrderPay addPay = orderPayDao.queryNoPay(orderInfoMaster.getId(),orderPayBo.getPayType());
            //如果找不到订单支付信息创建一条支付信息
            if(addPay==null){
                addPay = createOrderPayNew(orderInfoList);
            }
            IllegalException.isTrue(OrderEnum.PayStatus.SUCCEED.getCode().equals(addPay.getTradeStatus()),"订单已支付不要重复支付");
            OrderPay update = new OrderPay();
            ParamException.isBlank(addPay.getId());
            update.setId(addPay.getId());
            update.setPayTimes(addPay.getPayTimes()+1);
            update.setTradeStatus(OrderEnum.PayStatus.PRE.getCode());
            update.setPayType(orderPayBo.getPayType());
            orderPayDao.updateByPrimaryKeySelective(update);
            orderPayDao.updateOrderStatus(update,orderInfoMaster.getId());
            return fundsPay(addPay,orderPayBo);
        }else {
            OrderInfoVo orderInfoVo = orderInfoServer.getUserOrder(orderPayBo.getOrderId(),orderPayBo.getOperator());
            IllegalException.isFalse(OrderEnum.OrderStatus.UN_PAY.getCode().equals(orderInfoVo.getStatus()));
            IllegalException.isTrue(Instant.now().isAfter(orderInfoVo.getExpirationTime()),"订单已经超时请重新下单");
            OrderPay addPay = orderPayDao.queryNoPay(orderPayBo.getOrderId(),orderPayBo.getPayType());
            //如果找不到订单支付信息创建一条支付信息
            if(addPay==null){
                addPay = createOrderPay(BeanConverUtils.convertBean(orderInfoVo,OrderInfo.class));
            }
            IllegalException.isTrue(OrderEnum.PayStatus.SUCCEED.getCode().equals(addPay.getTradeStatus()),"订单已支付不要重复支付");
            OrderPay update = new OrderPay();
            update.setId(addPay.getId());
            update.setPayTimes(addPay.getPayTimes()+1);
            update.setTradeStatus(OrderEnum.PayStatus.PRE.getCode());
            update.setPayType(orderPayBo.getPayType());
            orderPayDao.updateByPrimaryKeySelective(update);
            return fundsPay(addPay,orderPayBo);
        }
    }


    public String fundsPay(OrderPay orderPay,OrderPayBo payBo){
        PaymentCreAndPayBo orderPayBo = new PaymentCreAndPayBo();
        orderPayBo.setOrderId(orderPay.getId());
        orderPayBo.setNotifyMethod(RabbitMqConstants.ORDER_PAY_NOTIFY_QUEUE);
        orderPayBo.setOrderType(Integer.valueOf(OrderTypeEnum.shopping.getCode()));
        orderPayBo.setPayProduct(payBo.getProduct());
        orderPayBo.setPayOpenId(payBo.getOpenId());
        orderPayBo.setPayUserId(payBo.getOperator());
        orderPayBo.setPayUserName(payBo.getOperatorName());
        orderPayBo.setPaymentType(payBo.getPayType());
        orderPayBo.setProduct(orderPay.getProduct());
        orderPayBo.setExpirationTime(orderPay.getExpirationTime());
        orderPayBo.setTotalAmount(orderPay.getAmount());
        orderPayBo.setUserId(orderPay.getUserId());
        orderPayBo.setUserName(orderPay.getUserName());
        orderPayBo.setPayAppId(payBo.getAppId());
        return  fundsApi.crePayment(orderPayBo).getResult();
    }


    /**
     * 完成支付
     */
    public void completePayment(String fundsPayId,String payId,String traderNo,Integer payType){
        OrderPay orderPay = orderPayDao.selectByPrimaryKey(payId);
        ParamException.isNull(orderPay);
        ParamException.isFalse(OrderEnum.PayStatus.PRE.getCode().equals(orderPay.getTradeStatus()));
        orderPay.setTradeNo(traderNo);
        orderPay.setTradeStatus(OrderEnum.PayStatus.SUCCEED.getCode());
        orderPay.setPayType(payType);
        orderPay.setFundsPayId(fundsPayId);
        orderPayDao.updateByPrimaryKeySelective(orderPay);
        if(StrUtil.isNotEmpty(orderPay.getPhaseId())){
            orderPhaseServer.completePayment(orderPay.getPhaseId());
        }
        orderInfoServer.completePayment(orderPay);
        asyncOperation(orderPay.getOrderId());
    }

    public void asyncOperation(String orderId){
        OrderInfo orderInfo = orderInfoDao.selectByPrimaryKey(orderId);
        if (null != orderInfo) {
            //发送钉钉消息
            ((OrderPayServer) AopContext.currentProxy()).sendMsg(orderInfo,"");
            //发送短信
            ((OrderPayServer) AopContext.currentProxy()).sendSMS(orderInfo);
            //发送微信模板消息
            ((OrderPayServer) AopContext.currentProxy()).sendWechatMsg(orderInfo);
        }
        //变更销量
        ((OrderPayServer) AopContext.currentProxy()).changeSales(orderId,1);
    }

    @Async
    public void sendWechatMsg(OrderInfo orderInfo){
        if (null != orderInfo) {
            sendWechatToUser(orderInfo);
            sendWechatToShop(orderInfo);
        }
    }

    private void sendWechatToShop(OrderInfo orderInfo) {
        ShopVo shopVo = shopApi.getShopById(orderInfo.getShopId()).getResult();
        String openId = userApi.getWechatOpenId(shopVo.getUserId()).getResult();
        if (StrUtil.isNotEmpty(openId)) {
            Instant time = null == orderInfo.getPayTime() ? Instant.now() : orderInfo.getPayTime();
            String timeStr = DateUtil.formatDateTime(time);
            WxTemplateMsgBo template = new WxTemplateMsgBo();
            template.setTouser(openId);
            template.setTemplate_id(WechatTemplateEnum.SHOP_ORDER_REMINDER.getTemplateId());
            template.setTopcolor("#353535");
            WxTemplateMsgBo.TemplateData data = template.new TemplateData();
            data.setFirst(template.new Node("您的〖"+ orderInfo.getShopName()+"〗店铺有新的订单，请及时处理。","#54529E"));
            data.setKeyword1(template.new Node(orderInfo.getId(), "#54529E"));
            data.setKeyword2(template.new Node(orderInfo.getPayAmount()+"元", "#54529E"));
            data.setKeyword3(template.new Node(orderInfo.getUserName(), "#54529E"));
            data.setKeyword4(template.new Node(orderInfo.getMobile(), "#54529E"));
            data.setKeyword5(template.new Node(timeStr, "#54529E"));
            data.setRemark(template.new Node("请及时处理您的订单！","#353535"));
            template.setData(data);
            gateApi.tempMessagePush(template);
        }
    }

    private void sendWechatToUser(OrderInfo orderInfo) {
        String openId = userApi.getWechatOpenId(orderInfo.getUserId()).getResult();
        if (StrUtil.isNotEmpty(openId)) {
            Instant time = null == orderInfo.getPayTime() ? Instant.now() : orderInfo.getPayTime();
            String timeStr = DateUtil.formatDateTime(time);
            WxTemplateMsgBo template = new WxTemplateMsgBo();
            template.setTouser(openId);
            template.setTemplate_id(WechatTemplateEnum.PAY_SUCCESS.getTemplateId());
            template.setTopcolor("#353535");
            WxTemplateMsgBo.TemplateData data = template.new TemplateData();
            data.setFirst(template.new Node("尊敬的"+ orderInfo.getUserName()+"，您的订单已支付成功：","#54529E"));
            data.setKeyword1(template.new Node(orderInfo.getId(), "#54529E"));
            data.setKeyword2(template.new Node(orderInfo.getPayAmount()+"元", "#54529E"));
            data.setKeyword3(template.new Node(orderInfo.getShopName(), "#54529E"));
            data.setKeyword4(template.new Node(timeStr, "#54529E"));
            data.setRemark(template.new Node("感谢您的光顾，欢迎您下次再来！","#353535"));
            template.setData(data);
            gateApi.tempMessagePush(template);
        }
    }

    /**
     * 变更销量
     */
    @Async
    public void changeSales(String orderId,Integer type){
        List<OrderSpuVo>  orderSpuVos = orderSpuServer.getOrderSpu(orderId);
        ChangeStockBo changeStockBo = new ChangeStockBo();
        Map<String, Integer> skus = orderSpuVos.stream().
                collect(Collectors.toMap(OrderSpuVo::getSkuCode, skuList -> skuList.getSkuQty()));
        changeStockBo.setSkus(skus);
        changeStockBo.setType(type);
        goodsApi.changeSales(changeStockBo);
    }

    /**
     * 发送短信
     */
    @Async
    public void sendSMS(OrderInfo orderInfo){
        if (orderInfo != null && orderInfo.getPlatformTag() != null && orderInfo.getPlatformTag() == 1) {
            ShopVo shopVo = shopApi.getShopById(orderInfo.getShopId()).getResult();
            if (null != shopVo && StrUtil.isNotEmpty(shopVo.getUserTel())) {
                TempSentSmsBo bo = new TempSentSmsBo();
                bo.setToPhone(shopVo.getUserTel());
                bo.setTemplateCode(SmsTempCodeEnum.PAY_ORDER.getCode());
                List<String> list = new ArrayList<>();
                list.add(orderInfo.getId());
                bo.setTemplateParam(list);
                messageApi.sentSms(bo);
            }
        }
    }

    /**
     * 发送钉钉消息
     */
    @Async
    public void sendMsg(OrderInfo orderInfo,String msg){
        if (orderInfo != null && orderInfo.getPlatformTag() != null && orderInfo.getPlatformTag() == 0) {
            DingTalkBo bo1 = new DingTalkBo();
            bo1.setMessage(msg);
            bo1.setChannel(StatisticsEnum.channel.UN_SEND_COUNT.getId());
            rabbitTemplate.convertAndSend(RabbitMqConstants.DINGDING_TALK_MESSAGE, JSON.toJSONString(bo1));
        }
    }

    /**
     * 完成支付
     */
    public void completePaymentNew(OrderPaymentVo orderPaymentVo){
        OrderPay orderPay = orderPayDao.selectByPrimaryKey(orderPaymentVo.getOrderId());
        ParamException.isNull(orderPay);
        ParamException.isFalse(OrderEnum.PayStatus.PRE.getCode().equals(orderPay.getTradeStatus()));
        if (!orderPay.getOrderId().equals(orderPay.getMasterOrderId())){
            completePayment(orderPaymentVo.getId(),orderPay.getId(),orderPaymentVo.getTradeNo(),orderPaymentVo.getPayType());
        }else {
            OrderPay orderPay1=new OrderPay();
            orderPay1.setMasterOrderId(orderPay.getMasterOrderId());
            List<OrderPay> payList = orderPayDao.select(orderPay1);
            for (OrderPay orderPay2:payList) {
                if(orderPay2.getOrderId().equals(orderPay2.getMasterOrderId())){
                    OrderPay update = new OrderPay();
                    update.setId(orderPaymentVo.getOrderId());
                    update.setTradeNo(orderPaymentVo.getTradeNo());
                    update.setTradeStatus(OrderEnum.PayStatus.SUCCEED.getCode());
                    orderPayDao.updateByPrimaryKeySelective(update);
                }else{
                    completePayment(orderPaymentVo.getId(),orderPay2.getId(),orderPaymentVo.getTradeNo(),orderPaymentVo.getPayType());
                }
            }
        }
    }




    /**
     * 查询订单支付信息
     * @param orderId
     * @return
     */
    public OrderPaymentVo getOrderPay(String orderId){
        OrderPay orderPay = new OrderPay();
        orderPay.setOrderId(orderId);
        return BeanConverUtils.convertBean(orderPayDao.selectOne(orderPay), OrderPaymentVo.class);
    }



}
